home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 001 / pibt40s3.arc / PIBMUSIC.MOD < prev    next >
Text File  |  1987-02-25  |  16KB  |  398 lines

  1.  
  2. (*----------------------------------------------------------------------*)
  3. (*                 Global variables for music playing                   *)
  4. (*----------------------------------------------------------------------*)
  5.  
  6. (* STRUCTURED *) CONST
  7.                                    (* Current Octave for Note *)
  8.    Note_Octave   : INTEGER = 4;
  9.                                    (* Fraction of duration given to note *)
  10.    Note_Fraction : REAL    = 0.875;
  11.                                    (* Duration of note *)
  12.    Note_Duration : INTEGER = 0;
  13.                                    (* Length of note *)
  14.    Note_Length   : REAL    = 0.25;
  15.                                    (* Length of quarter note (principal beat) *)
  16.    Note_Quarter  : REAL    = 500.0;
  17.  
  18. (* ------------------------------------------------------------------------ *)
  19. (*               PibPlaySet --- Set up to play music                        *)
  20. (*               PibPlay    --- Play Music through Speaker                  *)
  21. (* ------------------------------------------------------------------------ *)
  22.  
  23. PROCEDURE PibPlaySet;
  24.  
  25. (* ------------------------------------------------------------------------ *)
  26. (*                                                                          *)
  27. (*   Procedure:  PibPlaySet                                                 *)
  28. (*                                                                          *)
  29. (*   Purpose:    Sets up to play music though PC's speaker                  *)
  30. (*                                                                          *)
  31. (*   Calling Sequence:                                                      *)
  32. (*                                                                          *)
  33. (*      PibPlaySet;                                                         *)
  34. (*                                                                          *)
  35. (*   Calls:  None                                                           *)
  36. (*                                                                          *)
  37. (* ------------------------------------------------------------------------ *)
  38.  
  39. BEGIN (* PibPlaySet *)
  40.  
  41.                                    (* Default Octave *)
  42.    Note_Octave   := 4;
  43.                                    (* Default sustain is semi-legato *)
  44.    Note_Fraction := 0.875;
  45.                                    (* Note is quarter note by default *)
  46.    Note_Length   := 0.25;
  47.                                    (* Moderato pace by default *)
  48.    Note_Quarter  := 500.0;
  49.  
  50. END   (* PibPlaySet *);
  51.  
  52. PROCEDURE PibPlay( S : AnyStr );
  53.  
  54. (* ------------------------------------------------------------------------ *)
  55. (*                                                                          *)
  56. (*   Procedure:  PibPlay                                                    *)
  57. (*                                                                          *)
  58. (*   Purpose:    Play music though PC's speaker                             *)
  59. (*                                                                          *)
  60. (*   Calling Sequence:                                                      *)
  61. (*                                                                          *)
  62. (*      PibPlay( Music_String : AnyStr );                                   *)
  63. (*                                                                          *)
  64. (*         Music_String --- The string containing the encoded music to be   *)
  65. (*                          played.  The format is the same as that of the  *)
  66. (*                          MicroSoft Basic PLAY Statement.  The string     *)
  67. (*                          must be <= 254 characters in length.            *)
  68. (*                                                                          *)
  69. (*   Calls:  Sound                                                          *)
  70. (*           GetInt  (Internal)                                             *)
  71. (*                                                                          *)
  72. (*   Remarks:  The characters accepted by this routine are:                 *)
  73. (*                                                                          *)
  74. (*             A - G       Musical Notes                                    *)
  75. (*             # or +      Following A - G note,  indicates sharp           *)
  76. (*             -           Following A - G note,  indicates flat            *)
  77. (*             <           Move down one octave                             *)
  78. (*             >           Move up one octave                               *)
  79. (*             .           Dot previous note (extend note duration by 3/2)  *)
  80. (*             MN          Normal duration (7/8 of interval between notes)  *)
  81. (*             MS          Staccato duration                                *)
  82. (*             ML          Legato duration                                  *)
  83. (*             Ln          Length of note (n=1-64; 1=whole note,            *)
  84. (*                                         4=quarter note, etc.)            *)
  85. (*             Pn          Pause length (same n values as Ln above)         *)
  86. (*             Tn          Tempo, n=notes/minute (n=32-255, default n=120)  *)
  87. (*             On          Octave number (n=0-6, default n=4)               *)
  88. (*             Nn          Play note number n (n=0-84)                      *)
  89. (*                                                                          *)
  90. (*             The following two commands are IGNORED by PibPlay:           *)
  91. (*                                                                          *)
  92. (*             MF          Complete note before continuing                  *)
  93. (*             MB          Another process may begin before speaker is      *)
  94. (*                         finished playing note                            *)
  95. (*                                                                          *)
  96. (*   IMPORTANT --- PibPlaySet MUST have been called at least once before    *)
  97. (*                 this routine is called.                                  *)
  98. (*                                                                          *)
  99. (* ------------------------------------------------------------------------ *)
  100.  
  101. (* STRUCTURED *) CONST
  102.                                    (* Offsets in octave of natural notes *)
  103.  
  104.    Note_Offset   : ARRAY[ 'A'..'G' ] OF INTEGER
  105.                    = ( 9, 11, 0, 2, 4, 5, 7 );
  106.  
  107.                                    (* Frequencies for 7 octaves *)
  108.  
  109.    Note_Freqs: ARRAY[ 0 .. 84 ] OF INTEGER
  110.                =
  111. (*
  112.       C    C#     D    D#     E     F    F#     G    G#     A    A#     B
  113. *)
  114. (     0,
  115.      65,   69,   73,   78,   82,   87,   92,   98,  104,  110,  116,  123,
  116.     131,  139,  147,  156,  165,  175,  185,  196,  208,  220,  233,  247,
  117.     262,  278,  294,  312,  330,  350,  370,  392,  416,  440,  466,  494,
  118.     524,  556,  588,  624,  660,  700,  740,  784,  832,  880,  932,  988,
  119.    1048, 1112, 1176, 1248, 1320, 1400, 1480, 1568, 1664, 1760, 1864, 1976,
  120.    2096, 2224, 2352, 2496, 2640, 2800, 2960, 3136, 3328, 3520, 3728, 3952,
  121.    4192, 4448, 4704, 4992, 5280, 5600, 5920, 6272, 6656, 7040, 7456, 7904  );
  122.  
  123.    Quarter_Note = 0.25;            (* Length of a quarter note *)
  124.  
  125.    Digits : SET OF '0'..'9' = ['0'..'9'];
  126.  
  127. VAR
  128.                                    (* Frequency of note to be played *)
  129.    Play_Freq     : INTEGER;
  130.  
  131.                                    (* Duration to sound note *)
  132.    Play_Duration : INTEGER;
  133.  
  134.                                    (* Duration of rest after a note *)
  135.    Rest_Duration : INTEGER;
  136.  
  137.                                    (* Offset in Music string *)
  138.    I             : INTEGER;
  139.                                    (* Current character in music string *)
  140.    C             : CHAR;
  141.                                    (* Note Frequencies *)
  142.  
  143.    Freq          : ARRAY[ 0 .. 6 , 0 .. 11 ] OF INTEGER ABSOLUTE Note_Freqs;
  144.  
  145.    N             : INTEGER;
  146.    XN            : REAL;
  147.    K             : INTEGER;
  148.  
  149. (* ------------------------------------------------------------------------ *)
  150.  
  151. FUNCTION GetInt : INTEGER;
  152.  
  153. (*   --- Get integer from music string --- *)
  154.  
  155. VAR
  156.    N : INTEGER;
  157.  
  158. BEGIN (* GetInt *)
  159.  
  160.    N := 0;
  161.  
  162.    WHILE( S[I] IN Digits ) DO
  163.       BEGIN
  164.          N := N * 10 + ORD( S[I] ) - ORD('0');
  165.          I := SUCC( I );
  166.       END;
  167.  
  168.    I      := PRED( I );
  169.  
  170.    GetInt := N;
  171.  
  172. END   (* GetInt *);
  173.  
  174. (* ------------------------------------------------------------------------ *)
  175.  
  176. BEGIN (* PibPlay *)
  177.                                    (* Append blank to end of music string *)
  178.    S := S + ' ';
  179.                                    (* Point to first character in music *)
  180.    I := 1;
  181.                                    (* BEGIN loop over music string *)
  182.    WHILE( I < LENGTH( S ) ) DO
  183.  
  184.       BEGIN (* Interpret Music *)
  185.                                    (* Get next character in music string *)
  186.          C := UpCase(S[I]);
  187.                                    (* Interpret it                       *)
  188.          CASE C OF
  189.  
  190.             'A'..'G' : BEGIN (* A Note *)
  191.  
  192.                           N         := Note_Offset[ C ];
  193.  
  194.                           Play_Freq := Freq[ Note_Octave , N ];
  195.  
  196.                           XN := Note_Quarter * ( Note_Length / Quarter_Note );
  197.  
  198.                           Play_Duration := TRUNC( XN * Note_Fraction );
  199.  
  200.                           Rest_Duration := TRUNC( XN * ( 1.0 - Note_Fraction ) );
  201.  
  202.                                    (* Check for sharp/flat *)
  203.  
  204.                           IF S[I+1] IN ['#','+','-' ] THEN
  205.                              BEGIN
  206.  
  207.                                 I := SUCC( I );
  208.  
  209.                                 CASE S[I] OF
  210.                                    '#',
  211.                                    '+' : Play_Freq :=
  212.                                             Freq[ Note_Octave , SUCC( N ) ];
  213.                                    '-' : Play_Freq :=
  214.                                             Freq[ Note_Octave , PRED( N ) ];
  215.                                    ELSE  ;
  216.                                 END (* Case *);
  217.  
  218.                              END;
  219.  
  220.                                    (* Check for note length *)
  221.  
  222.                           IF ( S[I+1] IN Digits ) THEN
  223.                              BEGIN
  224.  
  225.                                 I  := SUCC( I );
  226.                                 N  := GetInt;
  227.                                 XN := ( 1.0 / N ) / Quarter_Note;
  228.  
  229.                                 Play_Duration :=
  230.                                     TRUNC( Note_Fraction * Note_Quarter * XN );
  231.  
  232.                                 Rest_Duration :=
  233.                                    TRUNC( ( 1.0 - Note_Fraction ) *
  234.                                           Xn * Note_Quarter );
  235.  
  236.                              END;
  237.                                    (* Check for dotting *)
  238.  
  239.                              IF S[I+1] = '.' THEN
  240.                                 BEGIN
  241.  
  242.                                    XN := 1.0;
  243.  
  244.                                    WHILE( S[I+1] = '.' ) DO
  245.                                       BEGIN
  246.                                          XN := XN * 1.5;
  247.                                          I  := SUCC( I );
  248.                                       END;
  249.  
  250.                                    Play_Duration :=
  251.                                        TRUNC( Play_Duration * XN );
  252.  
  253.                                 END;
  254.  
  255.                                        (* Play the note *)
  256.  
  257.                           Sound( Play_Freq );
  258.                           Delay( Play_Duration );
  259.                           NoSound;
  260.                           Delay( Rest_Duration );
  261.  
  262.                        END   (* A Note *);
  263.  
  264.             'M'      : BEGIN (* 'M' Commands *)
  265.  
  266.                           I := SUCC( I );
  267.                           C := S[I];
  268.  
  269.                           Case C Of
  270.  
  271.                              'F' : ;
  272.                              'B' : ;
  273.                              'N' : Note_Fraction := 0.875;
  274.                              'L' : Note_Fraction := 1.000;
  275.                              'S' : Note_Fraction := 0.750;
  276.                              ELSE ;
  277.  
  278.                           END (* Case *);
  279.  
  280.  
  281.                        END   (* 'M' Commands *);
  282.  
  283.             'O'      : BEGIN (* Set Octave *)
  284.  
  285.                           I := SUCC( I );
  286.                           N := ORD( S[I] ) - ORD('0');
  287.  
  288.                           IF ( N < 0 ) OR ( N > 6 ) THEN N := 4;
  289.  
  290.                           Note_Octave := N;
  291.  
  292.                        END   (* Set Octave *);
  293.  
  294.             '<'      : BEGIN (* Drop an octave *)
  295.  
  296.                           IF Note_Octave > 0 THEN
  297.                              Note_Octave := PRED( Note_Octave );
  298.  
  299.                        END   (* Drop an octave *);
  300.  
  301.             '>'      : BEGIN (* Ascend an octave *)
  302.  
  303.                           IF Note_Octave < 6 THEN
  304.                              Note_Octave := SUCC( Note_Octave );
  305.  
  306.                        END   (* Ascend an octave *);
  307.  
  308.             'N'      : BEGIN (* Play Note N *)
  309.  
  310.                           I := SUCC( I );
  311.  
  312.                           N := GetInt;
  313.  
  314.                           IF ( N > 0 ) AND ( N <= 84 ) THEN
  315.                              BEGIN
  316.  
  317.                                 Play_Freq    := Note_Freqs[ N ];
  318.  
  319.                                 XN           := Note_Quarter *
  320.                                                 ( Note_Length / Quarter_Note );
  321.  
  322.                                 Play_Duration := TRUNC( XN * Note_Fraction );
  323.  
  324.                                 Rest_Duration := TRUNC( XN * ( 1.0 - Note_Fraction ) );
  325.  
  326.                              END
  327.  
  328.                           ELSE IF ( N = 0 ) THEN
  329.                              BEGIN
  330.  
  331.                                 Play_Freq     := 0;
  332.                                 Play_Duration := 0;
  333.                                 Rest_Duration :=
  334.                                    TRUNC( Note_Fraction * Note_Quarter *
  335.                                           ( Note_Length / Quarter_Note ) );
  336.  
  337.                              END;
  338.  
  339.                           Sound( Play_Freq );
  340.                           Delay( Play_Duration );
  341.                           NoSound;
  342.                           Delay( Rest_Duration );
  343.  
  344.                        END   (* Play Note N *);
  345.  
  346.             'L'      : BEGIN (* Set Length of Notes *)
  347.  
  348.                           I := SUCC( I );
  349.                           N := GetInt;
  350.  
  351.                           IF N > 0 THEN Note_Length := 1.0 / N;
  352.  
  353.                        END   (* Set Length of Notes *);
  354.  
  355.             'T'      : BEGIN (* # of quarter notes in a minute *)
  356.  
  357.                           I := SUCC( I );
  358.                           N := GetInt;
  359.  
  360.                           Note_Quarter := ( 1092.0 / 18.2 / N ) * 1000.0;
  361.  
  362.                        END   (* # of quarter notes in a minute *);
  363.  
  364.             'P'      : BEGIN (* Pause *)
  365.  
  366.                           I := SUCC( I );
  367.                           N := GetInt;
  368.  
  369.                           IF      ( N <  1 ) THEN N := 1
  370.                           ELSE IF ( N > 64 ) THEN N := 64;
  371.  
  372.                           Play_Freq     := 0;
  373.                           Play_Duration := 0;
  374.                           Rest_Duration :=
  375.                              TRUNC( ( ( 1.0 / N ) / Quarter_Note )
  376.                                     * Note_Quarter );
  377.  
  378.                           Sound( Play_Freq );
  379.                           Delay( Play_Duration );
  380.                           NoSound;
  381.                           Delay( Rest_Duration );
  382.  
  383.                        END   (* Pause *);
  384.  
  385.             ELSE
  386.                (* Ignore other stuff *);
  387.  
  388.          END (* Case *);
  389.  
  390.          I := SUCC( I );
  391.  
  392.        END  (* Interpret Music *);
  393.  
  394.                                    (* Make sure sound turned off when through *)
  395.    NoSound;
  396.  
  397. END   (* PibPlay *);
  398.